
package msu.ml.util;

import java.io.*;
import org.w3c.dom.*;


public class DataUtility
{

    public static void calcFeatures(double [][][] values, int window)
    {
        for(int i = 0; i < values.length; i++)
        {
            for(int j = 0; j < values[i].length; j++)
            {
                double mean = calcMean(values, i, j, window);
                values[i][j][1] = calcVariance(values, i, j, mean, window);
                values[i][j][2] = calcSkewness(values, i, j, mean, window);
                values[i][j][3] = calcKurtosis(values, i, j, mean, window);
            }
        }
    }

    public static double calcMean(double [][][] values, int ray, int range, int window)
    {
        if(values.length == 0)
            return 0.0;

        int w = (window / 2);
        int n = 0;

        double sum = 0;
        for(int i = ray - w; i < ray + w; i++)
        {
            int iAdjusted = i;

            if(i < 0)
                iAdjusted = values.length + i;

            if(i >= values.length)
                iAdjusted = (i % values.length);

            for(int j = range - w; j < range + w; j++)
            {
                if(j > 0 && j < values[iAdjusted].length)
                {
                    sum += values[iAdjusted][j][0];
                    n++;
                }
            }
        }

        return sum / (double)n;
    }

    public static double calcMean(double [] values)
    {
        if(values.length == 0) return 0;

        double sum = 0;
        for(int i = 0; i < values.length; i++)
            sum += values[i];
        return  sum / values.length;
    }

    public static double calcVariance(double [] values)
    {
        return calcVariance(values, calcMean(values));
    }

    public static double calcVariance(double [] values, double mean)
    {
        if(values.length == 0) return 0;

        double n = values.length;
        double sum = 0;

        for(int i = 0; i < n; i++)
            sum += (values[i] * values[i]);
        return (sum - n * mean * mean) / n;
    }

    public static double calcVariance(double [][][] values, int ray, int range, double mean, int window)
    {
        if(values.length == 0)
            return 0;

        int w = (window / 2);
        int n = 0;

        double sum = 0;
        for(int i = ray - w; i < ray + w; i++)
        {
            int iAdjusted = i;
            if(i < 0)
                iAdjusted = values.length + i;
            if(i >= values.length)
                iAdjusted = i % values.length;

            for(int j = range - w; j < range + w; j++)
            {
                if(j > 0 && j < values[iAdjusted].length)
                {
                    double temp = values[iAdjusted][j][0]; 
                    sum += ((temp - mean) * (temp - mean));
                    n++;
                }
            }
        }

        return sum / (double)n;
    }

    public static double calcKurtosis(double [] values)
    {
        return calcKurtosis(values, calcMean(values));
    }

    public static double calcKurtosis(double [] values, double mean)
    {
        return calcFeature(values, mean, 4.0) - 3;
    }

    public static double calcKurtosis(double [][][] values, int ray, int range, double mean, int window)
    {
        return calcFeature(values, ray, range, mean, window, 4.0) - 3;
    }

    public static double calcSkewness(double [] values)
    {
        return calcSkewness(values, calcMean(values));
    }

    public static double calcSkewness(double [] values, double mean)
    {
        return calcFeature(values, mean, 3.0);
    }

    public static double calcSkewness(double [][][] values, int ray, int range, double mean, int window)
    {
        return calcFeature(values, ray, range, mean, window, 3.0);
    }

    private static double calcFeature(double [] values, 
            double mean, double order)
    {
        if(values.length == 0) return 0;

        double n = values.length;
        double num = 0;

        for(int i = 0; i < n; i++)
            num += Math.pow(values[i] - mean, order);

        double den = (n - 1) * Math.pow(Math.sqrt(
                    calcVariance(values, mean)), order);

        return den == 0 ? 0 : (num / den);
    }

    public static double calcFeature(double [][][] values, int ray, int range, double mean, int window, double order)
    {
        if(values.length == 0)
            return 0;

        int w = (window / 2);
        int n = 0;
        double num = 0, den = 0;

        for(int i = ray - w; i < ray + w; i++)
        {
            int iAdjusted = i;
            if(i < 0)
                iAdjusted = values.length + i;
            if(i >= values.length)
                iAdjusted = i % values.length;

            for(int j = range - w; j < range + w; j++)
            {
                if(j > 0 && j < values[iAdjusted].length)
                {
                    num += Math.pow(values[iAdjusted][j][0] - mean, order);
                    n++;
                }
            }
        }

        den = ((double)n - 1.0) * Math.pow(Math.sqrt(values[ray][range][1]), order);

        return den == 0 ? 0 : (num / den);
    }

    public static int lookupClass(String target)
    {
        String directory = target.substring(0, 
                target.lastIndexOf(File.separatorChar));
        String targetBase = target.substring(
                target.lastIndexOf(File.separatorChar) + 1);
        NodeList list = XmlUtility.xPathQuery(directory + 
                File.separatorChar + "classes.xml", "//sweep[@id = '" + 
                targetBase + "']/@class");
        return Integer.parseInt(list.item(0).getNodeValue());
    }
}
